package com.ujoku.controller;


import com.labillusion.core.platform.crypto.MD5;
import com.labillusion.core.platform.exception.ResourceNotFoundException;
import com.labillusion.core.platform.web.rest.RESTController;
import com.labillusion.core.platform.web.rest.exception.InvalidRequestException;
import com.ujoku.context.ActionContext;
import com.ujoku.domain.*;
import com.ujoku.interceptor.LoginRequired;
import com.ujoku.payment.alipay.AlipayCore;
import com.ujoku.payment.alipay.AlipaySubmit;
import com.ujoku.payment.chinaBank.ChinaBankConfig;
import com.ujoku.payment.chinaBank.ChinaBankCore;
import com.ujoku.payment.weChat.common.Configure;
import com.ujoku.payment.weChat.common.Util;
import com.ujoku.payment.weChat.protocol.app_pay_protocol.AppPayProtocol;
import com.ujoku.payment.weChat.protocol.uni_order_protocol.UniOrderReqData;
import com.ujoku.payment.weChat.protocol.uni_order_protocol.UniOrderResData;
import com.ujoku.payment.weChat.service.UniOrderService;
import com.ujoku.payment.weChat.utils.PayCommonUtil;
import com.ujoku.payment.weChat.utils.XMLUtil;
import com.ujoku.request.CreateOrderPaymentForm;
import com.ujoku.request.PaymentReturnForm;
import com.ujoku.request.PaymentSendForm;
import com.ujoku.service.OrderPaymentService;
import com.ujoku.service.OrderService;
import com.ujoku.view.domain.ChinaBankFormView;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;


@RestController
public class PaymentController extends RESTController {

    private final Logger logger = LoggerFactory.getLogger(PaymentController.class);

    @Autowired
    private OrderPaymentService orderPaymentService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private ActionContext actionContext;

    @Value("#{configProperties['settings.wxpayCallback.domain']}")
    private String notify_url;

    @RequestMapping(value="/orderPayment", method = RequestMethod.POST)
    @LoginRequired
    @ResponseBody
    public OrderPayment create(@RequestBody @Valid CreateOrderPaymentForm form) throws Exception {
        Member member = actionContext.getMember();
        Order order = orderService.selectById(form.getOrderId(), member.getUser_id());

        setUsedBalanceAmount(form.isUseBalance(), member, order);

        OrderPayment orderPayment = orderPaymentService.buildOrderPayment(order, form.getPaymentType(),null);

        if("WXpay".equals(form.getPaymentType())){
            UniOrderResData uniOrderResData = wxSendCommon(order,1);
            this.SetConfigure("wx1009e73690d2c24e","1222101801","e766cd646c02b496d2c7e810d0b6ba37");
            AppPayProtocol appPayProtocol = new AppPayProtocol(uniOrderResData.getPrepay_id());
            orderPayment.setAppPayProtocol(appPayProtocol);
        }

        return orderPayment;
    }


    //全款余额支付
    @RequestMapping(value="/balance/charge/{orderId}", method = RequestMethod.POST)
    @LoginRequired
    @ResponseBody
    public String balanceCharge(@PathVariable String orderId) {
        Member member = actionContext.getMember();
        Order order = orderService.selectById(orderId, member.getUser_id());

        if(order == null)
            throw new ResourceNotFoundException("can not found order");

        if(member.getBalance() < order.getTotal())
        {
            throw new InvalidRequestException("balance is not enough");
        }

        order.setUsedBalanceAmount(order.getTotal());
        orderPaymentService.orderComplete(null, PaymentType.Balance, order);

        return "success";
    }

    @RequestMapping(value="/chinaBank", method = RequestMethod.POST)
    @LoginRequired
    @ResponseBody
    public ChinaBankFormView chinaBankSend(@RequestBody @Valid PaymentSendForm form, HttpServletRequest request) {
        Member member = actionContext.getMember();

        Order order = orderService.selectById(form.getOrderId(), member.getUser_id());

        OrderPayment orderPayment = orderPaymentService.buildOrderPayment(order, PaymentType.Alipay,null);

        ChinaBankFormView view = new ChinaBankFormView();

        view.setMap(ChinaBankCore.buildRequestMap(request, orderPayment, form.getReturn_url()));
        return  view;
    }

    @RequestMapping(value="/chinaBank/return", method = RequestMethod.POST)
    @LoginRequired
    public String chinaBankReturn(@RequestBody @Valid PaymentReturnForm form){
        Member member = actionContext.getMember();
        Map<String,String> map = form.getParams();
        map.put("text",map.get("v_oid")+map.get("v_pstatus")+map.get("v_amount")+map.get("v_moneytype") + ChinaBankConfig.key);

        String v_md5 = MD5.encrypt(map.get("text")).toUpperCase();
        if (! map.get("v_md5str").equals(v_md5))
            throw new InvalidRequestException("非法请求!");

        Order order = orderService.selectById(map.get("v_oid"), member.getUser_id());
        if(order.getStatus() > OrderStatus.Created)
            return "/orderDetail/" + order.getId();

        boolean success = "20".equals(map.get("v_pstatus"));
        if(success){
            orderPaymentService.orderComplete(map.get("v_pmode"), PaymentType.UnionPay, order);
        }
        return "success";
    }

    @RequestMapping(value="/chinaBank/notify")
    @ResponseBody
    public String chinaBankAutoReceive(HttpServletRequest request) throws UnsupportedEncodingException {
        Map<String,String> map = ChinaBankCore.buildRequestMap(request);

        if( "30".equals(map.get("v_pstatus")))
            return "error";

        String v_md5 = MD5.encrypt(map.get("text")).toUpperCase();
        if (! map.get("v_md5str").equals(v_md5))
            throw new InvalidRequestException("非法请求!");

        Order order = (Order) orderService.selectById(map.get("v_oid"));
        if(order.getStatus() > OrderStatus.Created)
            return "/orderDetail/" + order.getId();

        boolean success = "20".equals(map.get("v_pstatus"));
        if(success){
            orderPaymentService.orderComplete(map.get("v_pmode"),PaymentType.UnionPay, order);
        }

        return "ok";
    }

    @RequestMapping(value="/alipay", method = RequestMethod.POST)
    @LoginRequired
    @ResponseBody
    public String alipaySend(@RequestBody @Valid PaymentSendForm form, HttpServletRequest request) {
        Member member = actionContext.getMember();

        Order order = orderService.selectById(form.getOrderId(), member.getUser_id());
        setUsedBalanceAmount(form.isUseBalance(), member, order);

        OrderPayment orderPayment = orderPaymentService.buildOrderPayment(order, PaymentType.Alipay,null);

        Map<String, String> sParaTemp = AlipayCore.buildRequestMap(request, orderPayment, form.getReturn_url());

        //建立请求
        String sHtmlText = AlipaySubmit.buildRequest(sParaTemp, "get", "确认");
        return sHtmlText;
    }

    private void setUsedBalanceAmount(Boolean useBalance, Member member, Order order) {
        if(useBalance){
            Double balance  = member.getBalance();
            if(balance > order.getTotal()){
                throw new InvalidRequestException("if customer balance is more than total, please use /balance/charge endpoint.");
            }
            else{
                order.setUsedBalanceAmount(balance);
            }
        }
        else{
            order.setUsedBalanceAmount(0d);
        }
        orderService.update(order);
    }

    @RequestMapping(value="/alipay/return", method = RequestMethod.POST)
    @ResponseBody
    public String alipayReturn(@RequestBody @Valid PaymentReturnForm form){
        Member member = actionContext.getMember();
        AlipayCore.verifyReturnRequest(form.getParams());

        Map<String,String> params = form.getParams();
        //商户订单号
        String out_trade_no = params.get("out_trade_no");
        //支付宝交易号
        String trade_no = params.get("trade_no");
        //交易状态
        String trade_status = params.get("trade_status");
        Order order = orderService.selectById(out_trade_no, member.getUser_id());
        if(order.getStatus() > OrderStatus.Created)
            return "/orderDetail/" + order.getId();

        if(trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
            orderPaymentService.orderComplete(trade_no, PaymentType.Alipay, order);
        }

        return "success";
    }



    @RequestMapping(value="/alipay/notify")
    @ResponseBody
    public String alipayNotify(HttpServletRequest request) throws UnsupportedEncodingException {

        AlipayCore.verifyReturnRequest(request);

        //商户订单号
        String out_trade_no = request.getParameter("out_trade_no");
        //支付宝交易号
        String trade_no = request.getParameter("trade_no");
        //交易状态
        String trade_status = request.getParameter("trade_status");

        Order order = (Order) orderService.selectById(out_trade_no);
        if(order.getStatus() > OrderStatus.Created)
            return "success";

        if(trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {

            orderPaymentService.orderComplete(trade_no,  PaymentType.Alipay, order);
            return "success";
        }

        return "fail";
    }

    @RequestMapping(value="/WXpay", method = RequestMethod.POST)
    @LoginRequired
    @ResponseBody
    public String wxSend(@RequestBody @Valid PaymentSendForm form) throws Exception {
        Member member = actionContext.getMember();

        Order order = orderService.selectById(form.getOrderId(), member.getUser_id());
        setUsedBalanceAmount(form.isUseBalance(), member, order);
        UniOrderResData uniOrderResData = wxSendCommon(order,2);
        if(uniOrderResData == null)
            throw new InvalidRequestException("get code_url false");
        return uniOrderResData.getCode_url();
    }

    private UniOrderResData wxSendCommon(Order order,int type) throws Exception {
        int total_fee = (int)((order.getTotal() - order.getUsedBalanceAmount())*100);
        String trade_type;
        String body;
        String detail;

        if(type == 1) {
            this.SetConfigure("wx1009e73690d2c24e","1235586702","Ujoku0418FowtechColtdxiamencheng");
            trade_type = "APP";
            body = "优酒库订单";
            detail = order.getOrderItemList().get(0).getGoodsName() + "等 " + order.getOrderItemList().size() + "件商品";
        }else{
            this.SetConfigure("wxf388e7f932f10c31","10021228","ujoku0418FOWTECHCOltdxiamencheng");
            trade_type = "NATIVE";
            body = "优酒库订单";
            detail = order.getOrderItemList().get(0).getGoodsName() + "等 " + order.getOrderItemList().size() + "件商品";
        }

        Configure.setNotify_url(notify_url + "/wechatPay/callback");

        UniOrderReqData data = new UniOrderReqData(body,"",order.getId(),total_fee,"WEB",actionContext.getRequest().getRemoteAddr(),trade_type,String.valueOf(order.getOrderItemList().get(0).getGoodsId()),detail);
        UniOrderService uniOrderService = new UniOrderService();
        String responseString = uniOrderService.request(data);
        UniOrderResData uniOrderResData = (UniOrderResData) Util.getObjectFromXML(responseString, UniOrderResData.class);

        return uniOrderResData;
    }

    private void SetConfigure(String app_id,String mch_id,String key){
        Configure.setAppID(app_id);
        Configure.setMchID(mch_id);
        Configure.setKey(key);
    }

    @RequestMapping(value="/wechatPay/callback")
    @ResponseBody
    public void wxpayNotify(HttpServletRequest request,HttpServletResponse response) throws IOException, JDOMException {

        InputStream inStream = request.getInputStream();

        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }

        outSteam.close();
        inStream.close();

        String result  = new String(outSteam.toByteArray(),"utf-8");

        Map<Object, Object> map = XMLUtil.doXMLParse(result);
        for(Object keyValue : map.keySet()){
            System.out.println(keyValue+"="+map.get(keyValue));
        }
        if (map.get("result_code").toString().equalsIgnoreCase("SUCCESS")) {
            String orderId = map.get("out_trade_no").toString();
            String trade_no = map.get("transaction_id").toString();
            String device_info = map.get("device_info").toString();
            if("APP-IOS".equals(device_info)){
                orderId = orderId.substring(orderId.indexOf("-") + 1);
            }
            logger.warn("APP的订单号是" + orderId);
            Order order = (Order)orderService.selectById(orderId);
            if(order.getStatus() > OrderStatus.Created);
            else{
                orderPaymentService.orderComplete(trade_no,  PaymentType.WXpay, order);
            }
            response.getWriter().write(PayCommonUtil.setXML("SUCCESS", ""));   //告诉微信服务器，我收到信息了，不要在调用回调action了
            logger.debug("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");
        }
        else {
            throw new InvalidRequestException("微信付款失败");
        }

    }
}